﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace Tencent.OA.App
{
    public static class MvcSiteMapExtensions
    {
        #region PageTitle

        /// <summary>
        /// 根据mvc.sitemap 文件的定义生成页面标题。
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        public static string PageTitle(this HtmlHelper html)
        {
            return PageTitle(html, null);
        }

        /// <summary>
        /// 根据mvc.sitemap 文件的定义生成页面标题，并指定站点名称。
        /// </summary>
        /// <param name="html"></param>
        /// <param name="siteName"></param>
        /// <returns></returns>
        public static string PageTitle(this HtmlHelper html, string siteName)
        {
            return PageTitle(html, siteName, " - ");
        }

        /// <summary>
        /// 根据mvc.sitemap 文件的定义生成页面标题，并指定站点名称。
        /// </summary>
        /// <param name="html"></param>
        /// <param name="siteName"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string PageTitle(this HtmlHelper html, string siteName, string separator)
        {
            MvcSiteMapNode node = SiteMap.CurrentNode as MvcSiteMapNode;
            var curExecNode = ((MvcSiteMapProvider)SiteMap.Provider).FindControllerActionNode(node, html.ViewContext.RouteData.Values);
            if (curExecNode != null)
                node = curExecNode;

            if (string.IsNullOrEmpty(separator))
                separator = " - ";
            //if (string.IsNullOrEmpty(siteName))
            //    siteName = SiteMap.RootNode.Description;

            StringBuilder title = new StringBuilder();
            if (node != null && !string.IsNullOrEmpty(node.Title))
            {
                title.Append(node.Title);

                if (!string.IsNullOrEmpty(siteName))
                    title.Append(separator);
            }

            if (!string.IsNullOrEmpty(siteName))
                title.Append(siteName);
            return title.ToString();

        }

        #endregion

        #region Menu

        /// <summary>
        /// 获取页面的菜单。
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        public static MvcHtmlString Menu(this HtmlHelper htmlHelper)
        {
            return Menu(htmlHelper, null);
        }
        public static MvcHtmlString Menu(this HtmlHelper htmlHelper, string cssClass)
        {
            return Menu(htmlHelper, cssClass, null);
        }
        public static MvcHtmlString  Menu(this HtmlHelper htmlHelper, string cssClass, string currentMenuCssClass)
        {
            MvcSiteMapNode rootNode = SiteMap.RootNode as MvcSiteMapNode;
            StringBuilder menus = new StringBuilder();
            if (rootNode != null)
            {
                var currentNode = SiteMap.CurrentNode as MvcSiteMapNode;
                if (currentNode == null)
                    return MvcHtmlString.Empty;

                UrlHelper url = new UrlHelper(htmlHelper.ViewContext.RequestContext);

                string cur_node_class = "";
                bool selectedNode = false;
                var nodes = rootNode.ChildNodes;
                var httpContent = HttpContext.Current;
                var slct_class = (string.IsNullOrEmpty(currentMenuCssClass) ? "" : " class=\"" + currentMenuCssClass +  "\"");
                foreach (MvcSiteMapNode node in nodes)
                {
                    if (node.IsMenu && node.IsAccessibleToUser(httpContent))
                    {
                        if (IsCurrentNode(currentNode, node))
                        {
                            cur_node_class = slct_class;
                            selectedNode = true;
                        }
                        menus.AppendLine(string.Format("<li{0}><a href=\"{1}\">{2}</a></li>", cur_node_class, url.Content(node.Url), htmlHelper.Encode(node.Title)));
                        cur_node_class = "";
                    }
                }

                // 首先呈现首页。sitemap文件中，首页为顶层节点，则需单独呈现
                // 如果添加完其他所有节点后，还没有高亮显示当前菜单时，将首页设为高亮菜单
                //
                if (!selectedNode || rootNode == currentNode)
                    cur_node_class = slct_class;
                var ul_class = "";
                if (!string.IsNullOrEmpty(cssClass))
                    ul_class = " class=\"" + cssClass +  "\"";
                menus.Insert(0, string.Format("<ul{0}><li{1}><a href=\"{2}\">{3}</a></li>",
                    new string[] { ul_class, cur_node_class, url.Content(rootNode.Url), htmlHelper.Encode(rootNode.Title) }));
                menus.Append("</ul>");
            }
            return MvcHtmlString.Create(menus.ToString());
        }

        private static bool IsCurrentNode(MvcSiteMapNode currentNode, MvcSiteMapNode menuNode)
        {
            // 如果当前节点为菜单则直接比较是否相等
            if (currentNode == menuNode)
                return true;

            // 然后查找父节点，直到菜单节点
            var parentNode = currentNode.ParentNode as MvcSiteMapNode;
            while (parentNode != null)
            {
                if (parentNode.IsMenu)
                {
                    // 有可能还是二级菜单
                    var menu_Node = parentNode.ParentNode as MvcSiteMapNode;
                    if (menu_Node != null && menu_Node.IsMenu)
                        return menu_Node == menuNode;
                    return (parentNode == menuNode);
                }
                parentNode = parentNode.ParentNode as MvcSiteMapNode;
            }
            return false;
        }

        #endregion

        #region SiteMapPath

        public static string SiteMapPath(this HtmlHelper htmlHelper)
        {
            return SiteMapPath(htmlHelper, " &raquo; ");
        }

        public static string SiteMapPath(this HtmlHelper htmlHelper, string separator)
        {
            return SiteMapPath(htmlHelper, separator, false);
        }

        public static string SiteMapPath(this HtmlHelper htmlHelper, string separator, bool currentNodeAsLink)
        {
            return SiteMapPath(htmlHelper, separator, currentNodeAsLink, false);
        }

        public static string SiteMapPath(this HtmlHelper htmlHelper, string separator, bool currentNodeAsLink, bool showPathPrefix)
        {
            return SiteMapPath(htmlHelper, separator, currentNodeAsLink, showPathPrefix, null);
        }

        public static string SiteMapPath(this HtmlHelper htmlHelper, string separator, bool currentNodeAsLink, bool showPathPrefix, object htmlAttributes)
        {
            IDictionary<string, object> attr = new RouteValueDictionary(htmlAttributes);
            return SiteMapPath(htmlHelper, separator, currentNodeAsLink, showPathPrefix, null, null, attr);
        }

        public static string SiteMapPath(this HtmlHelper htmlHelper, string separator, bool currentNodeAsLink, bool showPathPrefix, string linkCssClass, string separatorCssClass, object htmlAttributes)
        {
            IDictionary<string, object> attr = new RouteValueDictionary(htmlAttributes);
            return SiteMapPath(htmlHelper, separator, currentNodeAsLink, showPathPrefix, linkCssClass, separatorCssClass, attr);
        }

        public static string SiteMapPath(this HtmlHelper htmlHelper, string separator, bool currentNodeAsLink, bool showPathPrefix, string linkCssClass, string separatorCssClass, IDictionary<string, object> htmlAttributesDictionary)
        {
            MvcSiteMapProvider provider = SiteMap.Provider as MvcSiteMapProvider;
            if (provider == null)
                throw new InvalidOperationException("组件仅支持类型为 MvcSiteMapProvider 的提供程序。");

            MvcSiteMapNode node = provider.CurrentNode as MvcSiteMapNode;

            // 首页不显示
            if (node == null || node == provider.RootNode)
                return string.Empty;

            var requestContext = htmlHelper.ViewContext.RequestContext;
            UrlHelper urlHelper = new UrlHelper(requestContext);

            // 查找实际执行当前请求的Action对应的sitemap节点
            MvcSiteMapNode currentExecuteNode = provider.FindControllerActionNode(node, requestContext.RouteData.Values);
            if (currentExecuteNode != null)
                node = currentExecuteNode;

            var pages = new List<string>();

            // 当前节点
            //
            if (currentNodeAsLink)
                pages.Add(SiteMapLink(htmlHelper, urlHelper, node, linkCssClass, htmlAttributesDictionary));
            else
                pages.Add(SiteMapText(htmlHelper, node, linkCssClass, htmlAttributesDictionary));

            var parentNode = node.ParentNode as MvcSiteMapNode;
            while (parentNode != null)
            {
                pages.Add(SiteMapLink(htmlHelper, urlHelper, parentNode, linkCssClass, htmlAttributesDictionary));
                parentNode = parentNode.ParentNode as MvcSiteMapNode;
            }
            pages.Reverse();

            var separatorHtml = separator;
            if (!string.IsNullOrEmpty(separatorCssClass))
            {
                separatorHtml = string.Format("<span class=\"{0}\">{1}</span>", separatorCssClass, separator);
            }
            string pathValue = string.Join(separatorHtml, pages.ToArray());
            if (showPathPrefix)
                pathValue = "当前位置：" + pathValue;
            return pathValue;
        }

        /// <summary>
        /// 生成字符串
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="node"></param>
        /// <param name="linkCssClass"></param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        private static string SiteMapText(HtmlHelper helper, MvcSiteMapNode node, string linkCssClass, IDictionary<string, object> htmlAttributes)
        {
            var extraAttributes = new StringBuilder();
            foreach (var attribute in htmlAttributes)
            {
                extraAttributes.Append(" " + attribute.Key + "=\"" + attribute.Value + "\"");
            }

            string text = node.Title;
            if (!string.IsNullOrEmpty(node.Description))
            {
                text = node.Description;
            }
            return string.Format("<span{0}{1}>{2}</span>",
                (string.IsNullOrEmpty(linkCssClass) ? "" : (" class=\"" + linkCssClass + "\"")),
                extraAttributes.ToString(),
                helper.Encode(text));
        }

        /// <summary>
        /// 生成导航的链接
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="node"></param>
        /// <param name="linkCssClass"></param>
        /// <param name="currentNodeAsLink"></param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        private static string SiteMapLink(HtmlHelper html, UrlHelper url, MvcSiteMapNode node, string linkCssClass, IDictionary<string, object> htmlAttributes)
        {
            if (node == null)
                throw new ArgumentNullException("node");

            var extraAttributes = new StringBuilder();
            if (!string.IsNullOrEmpty(linkCssClass))
            {
                extraAttributes.Append(" class=\"" + linkCssClass + "\"");
            }

            if (!string.IsNullOrEmpty(node.LinkTarget))
            {
                extraAttributes.Append(" target=\"" + node.LinkTarget + "\"");
            }

            string linkTitle = node.Title;
            //if (!string.IsNullOrEmpty(node.Description))
            //{
            //    linkTitle = node.Description;
            //}
            if (!string.IsNullOrEmpty(linkTitle))
            {
                extraAttributes.Append(" title=\"" + linkTitle + "\"");
            }
            foreach (var attribute in htmlAttributes)
            {
                extraAttributes.Append(" " + attribute.Key + "=\"" + attribute.Value + "\"");
            }

            return string.Format("<a href=\"{0}\"{1}>{2}</a>",
                url.Content(node.Url), extraAttributes, html.Encode(node.Title));
        }

        #endregion

        /// <summary>
        /// 获取XElement中指定属性名的值。
        /// </summary>
        /// <param name="node">当前的XElement节点。</param>
        /// <param name="attributeName">需要从中取值的属性名。</param>
        /// <returns></returns>
        internal static string GetAttributeValue(this XElement node, string attributeName)
        {
            var attribute = node.Attribute(attributeName);
            return attribute != null ? attribute.Value : string.Empty;
        }
    }
}
